`timescale 1ns / 1ps
/******************************************************************************
*                                                                             *
* UTICA softcore v0.1                                                         *
*                                                                             *
* Copyright (c) 2012 Andrew D. Zonenberg                                      *
* All rights reserved.                                                        *
*                                                                             *
* Redistribution and use in source and binary forms, with or without modifi-  *
* cation, are permitted provided that the following conditions are met:       *
*                                                                             *
*    * Redistributions of source code must retain the above copyright notice  *
*      this list of conditions and the following disclaimer.                  *
*                                                                             *
*    * Redistributions in binary form must reproduce the above copyright      *
*      notice, this list of conditions and the following disclaimer in the    *
*      documentation and/or other materials provided with the distribution.   *
*                                                                             *
*    * Neither the name of the author nor the names of any contributors may be*
*      used to endorse or promote products derived from this software without *
*      specific prior written permission.                                     *
*                                                                             *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF        *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN     *
* NO EVENT SHALL THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT,         *
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT    *
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,   *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY       *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT         *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF    *
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.           *
*                                                                             *
******************************************************************************/

/**
	@file L1Cache.v
	@author Andrew D. Zonenberg
	@brief A single L1 cache block, one instance each for the I- and D-side must be created.
	
	This is a very simplistic direct-mapped write-through implementation intended for testing cache miss handling in the CPU.
	Do not expect any kind of reasonable performance if it's used in a real system!
	
	1024 lines x 32 bits (32 Kbit / 4 KB) direct mapped. This means we have 4096 bytes or 12 bits of address.
	
	2x BRAM for data (end to end).
	
	12 bits address means we need 20 bits of tag. This is available by using 4 parity bits from the data RAMs plus 16 bits
	in a dedicated tag memory, half the width.
	
	Total resource usage - 3x BRAM
	
	DATA BLOCK									TAG BLOCK
	32 bits data + low 4 bits tag			16 bits tag + 1 bit valid flag + 1 bit unused
	
	Address breakdown
	High tag:	31:16
	Low tag:		15:12
	Address:		11:2
	Unused:		1:0 (must always be zero)
	
	Byte reads are easy - return the whole word and let the CPU sort it out. In fact, we don't even worry about byte
	reads because the CPU always reads on a per-word basis.
	
	Masked writes are harder. We are going to write the masked data through to the L2, of course, but we also need
	to write this data to the L1 memory. What to do if the L1 doesn't have the rest of the cache line? Options include
	* Write through only, don't cache the word at all (easy for testing)
	* Remember that we updated this word, then read the rest of the word, then patch it and store it (harder but more efficient)
	
	Since this cache is intended as a backup / placeholder / testbench we're going to take the first option.
	
	Uncacheable write		forward to L2
	Uncacheable read		forward to L2, then forward response
	Cached write			forward to L2, simultaneously writing to cache
	Cached read				Check for hit, then respond if hit.
								If miss, forward read to L2 and wait for response.
								We may have to stall up to 1 cycle because the CPU won't realize we stalled until the next clock.
								We can never have more than two outstanding requests, though.
								
	
	In all cases it's safe to throw away a cached read request if we really have to since none of them do anything irreversible.
						
 */
//uncomment for verbose debug output
//`define L1_CACHE_TRACE
module L1Cache(
	clk,
	cpu_addr, cpu_rd, cpu_wr, cpu_dout, cpu_wmask, cpu_din, cpu_dinok,						//CPU bus
	l2_addr,  l2_rd,  l2_wr,  l2_dout,   l2_wmask, l2_din,  l2_dinok							//L2 bus
    );

	////////////////////////////////////////////////////////////////////////////////////////////////
	// Global stuff
	
	input wire clk;
	
	////////////////////////////////////////////////////////////////////////////////////////////////
	// CPU to L1 bus
	input wire[31:0] cpu_addr;
	input wire cpu_rd;
	input wire cpu_wr;
	input wire[31:0] cpu_dout;
	input wire[3:0] cpu_wmask;
	output reg[31:0] cpu_din = 0;
	output reg cpu_dinok = 0;
	
	////////////////////////////////////////////////////////////////////////////////////////////////
	// L1 to L2 bus
	output reg[31:0] l2_addr = 0;
	output reg l2_rd = 0;
	output reg l2_wr = 0;
	input wire[31:0] l2_dout;
	output reg[31:0] l2_din = 0;
	output reg[3:0] l2_wmask = 0;
	input wire l2_dinok;										//asserted if data is valid
	
	//Buffer l2_addr so that we know what address the data came from
	reg[31:0] l2_addr_buf = 0;
	always @(posedge clk) begin
		l2_addr_buf <= l2_addr;
	end
	
	////////////////////////////////////////////////////////////////////////////////////////////////
	// Addressing and forwarding logic
		
	/*
		First cycle - dispatch read to SRAM bank
		Second cycle - response comes back, it's a miss. Immediately forward to L2.
		Third cycle - forward L2's response to CPU
	 */
	
	//If this flag is set, do not cache this request
	wire uncacheable;
	assign uncacheable = (cpu_addr[31:29] == 3'b101);
	
	wire cache_hit;
	
	reg[31:0] cpu_addr_buf = 0;
	reg uncacheable_buf = 0;
	always @(posedge clk) begin
		cpu_addr_buf <= cpu_addr;
		uncacheable_buf <= uncacheable;
	end

	//Check if we have a miss
	wire cache_miss = cpu_rd_buf && !cache_hit && !(forward_buf && l2_dinok);

	//L2 bus control
	wire forward;
	assign forward = uncacheable | cpu_wr;
	assign read_from_l2 = !forward ;//&& pending_read_enabled;
	
	always @(forward, cpu_addr, cpu_rd, cpu_wr, cpu_dout, cpu_wmask, cache_miss, cpu_addr_buf) begin
		
		//Forward requests from CPU bus directly to L2
		if(forward) begin
			l2_addr <= cpu_addr;
			l2_rd <= cpu_rd;
			l2_wr <= cpu_wr;
			l2_din <= cpu_dout;
			l2_wmask <= cpu_wmask;
		end

		//Reading from L2 in case of a cache miss
		else if(cache_miss) begin
			l2_addr <= cpu_addr_buf;
			l2_rd <= 1;
			
			l2_wr <= 1'b0;
			l2_din <= 32'b0;
			l2_wmask <= 32'b0;
		end
		
		//No, bus is idle
		else begin
			l2_addr <= 32'h0;
			l2_rd <= 1'b0;
			l2_wr <= 1'b0;
			l2_din <= 32'b0;
			l2_wmask <= 32'b0;
		end
	
	end
	
	//Buffer forwarding flag
	reg forward_buf = 0;
	always @(posedge clk) begin
		forward_buf <= forward;
	end
	
	wire[31:0] cache_dout;
	
	//Forwarding of responses to results
	always @(forward_buf, l2_dout, cache_dout, l2_dinok, cache_hit, cpu_rd_buf, cpu_addr_buf, l2_addr_buf) begin
		cpu_din <= 32'h0;
		cpu_dinok <= 0;
		
		if(forward_buf || (cpu_rd_buf && cpu_addr_buf == l2_addr_buf)) begin
			cpu_din <= l2_dout;
			cpu_dinok <= l2_dinok;
		end
				
		else if(cpu_rd_buf) begin
			cpu_din <= cache_dout;
			cpu_dinok <= cache_hit;
		end
		
	end
	
	//Remember if we were reading
	reg cpu_rd_buf = 0;
	reg l2_rd_buf = 0;
	always @(posedge clk) begin
		cpu_rd_buf <= cpu_rd;
		l2_rd_buf <= l2_rd;
	end
	
	////////////////////////////////////////////////////////////////////////////////////////////////
	// In-bank addressing and hit processing logic
	
	//Data from CPU to cache
	wire[35:0] cache_in_cpu;
	assign cache_in_cpu = {cpu_addr[15:12], cpu_dout};
	
	//BUGFIX: If we do have a partial write, flush the tag to invalid.
	wire full_word_write;
	assign full_word_write = (cpu_wmask == 4'b1111);
	
	//Tag data from CPU to cache
	//If the write is not a full word, just clear the valid bit
	wire[17:0] tag_in_cpu;
	assign tag_in_cpu = {1'b0, full_word_write, cpu_addr[31:16]};
	wire[17:0] tag_in_l2;
	assign tag_in_l2 = {1'b0, 1'b1, l2_addr_buf[31:16]};
	
	//Data from L2 to cache
	wire[35:0] cache_in_l2;
	assign cache_in_l2 = {l2_addr_buf[15:12], l2_dout};
	
	//Data from cache to output (needs to be muxed etc)
	wire[35:0] cache_out_low;
	wire[35:0] cache_out_high;
	
	//Mux output of the cache banks
	wire[35:0] cache_out;
	assign cache_out = cpu_addr_buf[11] ? cache_out_high : cache_out_low;
	assign cache_dout = cache_out[31:0];
	
	//Read and write enables
	wire cpu_en_low;
	wire l2_en_low;
	wire[3:0] cpu_we_low;
	wire[3:0] l2_we_low;
	wire cpu_en_high;
	wire l2_en_high;
	wire[3:0] cpu_we_high;
	wire[3:0] l2_we_high;
	
	//Check if we had any read-write collisions on the cache
	wire addr_collide;
	assign addr_collide = (cpu_addr[11:2] == l2_addr_buf[11:2]) && l2_rd_buf && l2_dinok;
	
	//Bit 11 of address is bank selector
	//But disable it in case of a collision!
	assign cpu_en_low = !cpu_addr[11] && !addr_collide;
	assign cpu_en_high = cpu_addr[11] && !addr_collide;
	
	assign l2_en_low = !l2_addr_buf[11] && l2_rd_buf;
	assign l2_en_high = l2_addr_buf[11] && l2_rd_buf;
	
	//Write enable
	wire cpu_we;
	wire[1:0] l2_we_tag;
	assign cpu_we = cpu_wr & !uncacheable;
	assign cpu_we_high = {cpu_we, cpu_we, cpu_we, cpu_we};
	assign cpu_we_low = {cpu_we, cpu_we, cpu_we, cpu_we};
	assign l2_we_low = {l2_dinok, l2_dinok, l2_dinok, l2_dinok};
	assign l2_we_high = {l2_dinok, l2_dinok, l2_dinok, l2_dinok};
	assign l2_we_tag = {l2_dinok, l2_dinok};
	
	wire[17:0] tag_out_high;
	
	//Reconstruct the tag data
	wire tag_valid = tag_out_high[16];
	wire[19:0] tag_out;
	assign tag_out = {tag_out_high[15:0], cache_out[35:32]};
	
	//See if the read (assuming there is one) returned a cache hit
	assign cache_hit = !uncacheable_buf && (tag_out == cpu_addr_buf[31:12]) && !addr_collide && tag_valid;
	
	////////////////////////////////////////////////////////////////////////////////////////////////
	// DATA BLOCKS
	//Default to all zeros	
	BRAM_TDP_MACRO #(
		.BRAM_SIZE("18Kb"),
		.DEVICE("SPARTAN6"),
		.DOA_REG(0),
		.DOB_REG(0),
		.INIT_A(36'h0000000),
		.INIT_B(36'h00000000),
		.INIT_FILE ("NONE"),
		.READ_WIDTH_A (36),
		.READ_WIDTH_B (36),
		.SIM_COLLISION_CHECK ("ALL"),
		.SRVAL_A(36'h00000000),
		.SRVAL_B(36'h00000000),
		.WRITE_MODE_A("WRITE_FIRST"),
		.WRITE_MODE_B("WRITE_FIRST"),
		.WRITE_WIDTH_A(36),
		.WRITE_WIDTH_B(36),
		.INIT_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_07(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_08(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_09(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0F(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_10(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_11(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_12(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_13(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_14(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_15(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_16(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_17(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_18(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_19(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1F(256'h0000000000000000000000000000000000000000000000000000000000000000),
			
		// The next set of INIT_xx are for "18Kb" configuration only
		.INIT_20(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_21(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_22(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_23(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_24(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_25(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_26(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_27(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_28(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_29(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2F(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_30(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_31(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_32(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_33(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_34(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_35(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_36(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_37(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_38(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_39(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3F(256'h0000000000000000000000000000000000000000000000000000000000000000),

		// The next set of INITP_xx are for the parity bits
		.INITP_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
			
		// The next set of INITP_xx are for "18Kb" configuration only
		.INITP_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_07(256'h0000000000000000000000000000000000000000000000000000000000000000)
	) data_block_low (
		.DOA(cache_out_low),
		//.DOB(DOB),					//L2 cannot read from us, only write
		.ADDRA(cpu_addr[10:2]),		//Pull appropriate bits of address out
		.ADDRB(l2_addr_buf[10:2]),
		.CLKA(clk),
		.CLKB(clk),
		.DIA(cache_in_cpu),
		.DIB(cache_in_l2),
		.ENA(cpu_en_low),
		.ENB(l2_en_low),
		.REGCEA(1'b1),
		.REGCEB(1'b1),
		.RSTA(1'b0),
		.RSTB(1'b0),
		.WEA(cpu_we_low),
		.WEB(l2_we_low)
		);
		
	BRAM_TDP_MACRO #(
		.BRAM_SIZE("18Kb"),
		.DEVICE("SPARTAN6"),
		.DOA_REG(0),
		.DOB_REG(0),
		.INIT_A(36'h0000000),
		.INIT_B(36'h00000000),
		.INIT_FILE ("NONE"),
		.READ_WIDTH_A (36),
		.READ_WIDTH_B (36),
		.SIM_COLLISION_CHECK ("ALL"),
		.SRVAL_A(36'h00000000),
		.SRVAL_B(36'h00000000),
		.WRITE_MODE_A("WRITE_FIRST"),
		.WRITE_MODE_B("WRITE_FIRST"),
		.WRITE_WIDTH_A(36),
		.WRITE_WIDTH_B(36),
		.INIT_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_07(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_08(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_09(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0F(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_10(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_11(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_12(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_13(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_14(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_15(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_16(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_17(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_18(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_19(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1F(256'h0000000000000000000000000000000000000000000000000000000000000000),
			
		// The next set of INIT_xx are for "18Kb" configuration only
		.INIT_20(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_21(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_22(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_23(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_24(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_25(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_26(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_27(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_28(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_29(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2F(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_30(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_31(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_32(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_33(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_34(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_35(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_36(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_37(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_38(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_39(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3F(256'h0000000000000000000000000000000000000000000000000000000000000000),

		// The next set of INITP_xx are for the parity bits
		.INITP_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
			
		// The next set of INITP_xx are for "18Kb" configuration only
		.INITP_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_07(256'h0000000000000000000000000000000000000000000000000000000000000000)
	) data_block_high (
		.DOA(cache_out_high),
		//.DOB(DOB),					//L2 cannot read from us, only write
		.ADDRA(cpu_addr[10:2]),		//Pull appropriate bits of address out
		.ADDRB(l2_addr_buf[10:2]),
		.CLKA(clk),
		.CLKB(clk),
		.DIA(cache_in_cpu),
		.DIB(cache_in_l2),
		.ENA(cpu_en_high),
		.ENB(l2_en_high),
		.REGCEA(1'b1),
		.REGCEB(1'b1),
		.RSTA(1'b0),
		.RSTB(1'b0),
		.WEA(cpu_we_high),
		.WEB(l2_we_high)
		);
		
	BRAM_TDP_MACRO #(
		.BRAM_SIZE("18Kb"),
		.DEVICE("SPARTAN6"),
		.DOA_REG(0),
		.DOB_REG(0),
		.INIT_A(18'h0000000),
		.INIT_B(18'h00000000),
		.INIT_FILE ("NONE"),
		.READ_WIDTH_A (18),
		.READ_WIDTH_B (18),
		.SIM_COLLISION_CHECK ("ALL"),
		.SRVAL_A(36'h00000000),
		.SRVAL_B(36'h00000000),
		.WRITE_MODE_A("WRITE_FIRST"),
		.WRITE_MODE_B("WRITE_FIRST"),
		.WRITE_WIDTH_A(18),
		.WRITE_WIDTH_B(18),
		.INIT_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_07(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_08(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_09(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_0F(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_10(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_11(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_12(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_13(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_14(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_15(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_16(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_17(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_18(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_19(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_1F(256'h0000000000000000000000000000000000000000000000000000000000000000),
			
		// The next set of INIT_xx are for "18Kb" configuration only
		.INIT_20(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_21(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_22(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_23(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_24(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_25(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_26(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_27(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_28(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_29(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_2F(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_30(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_31(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_32(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_33(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_34(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_35(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_36(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_37(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_38(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_39(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3A(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3B(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3C(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3D(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3E(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INIT_3F(256'h0000000000000000000000000000000000000000000000000000000000000000),

		// The next set of INITP_xx are for the parity bits
		.INITP_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
			
		// The next set of INITP_xx are for "18Kb" configuration only
		.INITP_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
		.INITP_07(256'h0000000000000000000000000000000000000000000000000000000000000000)
	) tag_block (
		.DOA(tag_out_high),
		//.DOB(DOB),					//L2 cannot read from us, only write
		.ADDRA(cpu_addr[11:2]),		//Pull appropriate bits of address out
		.ADDRB(l2_addr_buf[11:2]),
		.CLKA(clk),
		.CLKB(clk),
		.DIA(tag_in_cpu),
		.DIB(tag_in_l2),
		.ENA(!addr_collide),
		.ENB(l2_rd_buf),
		.REGCEA(1'b1),
		.REGCEB(1'b1),
		.RSTA(1'b0),
		.RSTB(1'b0),
		.WEA({cpu_we, cpu_we}),
		.WEB(l2_we_tag)
		);


endmodule
